home *** CD-ROM | disk | FTP | other *** search
/ Delphi Magazine Collection 2001 / Delphi Magazine Collection 20001 (2001).iso / DISKS / Issue49 / Factory / FactoryAbstract.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1999-06-22  |  11.5 KB  |  328 lines

  1. {* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  2.   TechInsite Pty. Ltd.
  3.   PO Box 429, Abbotsford, Melbourne. 3067 Australia
  4.   Phone: +61 3 9419 6456
  5.   Fax:   +61 3 9419 1682
  6.   Web:   www.techinsite.com.au
  7.   EMail: peter_hinrichsen@techinsite.com.au
  8.  
  9.   Created: 01/06/1999
  10.  
  11.   Notes: Abstract factory.
  12.          This factory will create TObject or TComponent descendants
  13.          Descend from this object, and write a new CreateInstance function to
  14.          create objects or components which have been type cast correctly.
  15.  
  16. * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *}
  17.  
  18. unit FactoryAbstract;
  19.  
  20. interface
  21. uses
  22.    Classes             // For TObject
  23.   ;
  24.  
  25. type
  26.  
  27.   // Class reference for TObject descendants
  28.   //----------------------------------------------------------------------------
  29.   TObjectClassRef = class of TObject ;
  30.  
  31.   // Class reference for TComponent descendants
  32.   //----------------------------------------------------------------------------
  33.   TComponentClassRef = class of TComponent ;
  34.  
  35.   // Tell the factory to create a TObject or a TComponent.
  36.   // This is necessary as TComponent descendents will need
  37.   // an owner parameter.
  38.   //----------------------------------------------------------------------------
  39.   TCreateAs = ( caTObject, caTComponent ) ;
  40.  
  41.   // After a class is registered with the factory, a
  42.   // TClassMappingAbstract descendant will be added to the
  43.   // list of registered objects.
  44.   //----------------------------------------------------------------------------
  45.   TClassMappingAbstract = class( TObject )
  46.   private
  47.     FStrClassID : string ;      // A string to identify the class
  48.     FCreateAs   : TCreateAs ;   // Create as a TObject or TComponent
  49.     FBoolSingleton : boolean ;  // Cache this instance ?
  50.   public
  51.     property    ClassID  : string read  FStrClassID
  52.                                   write FStrClassID ;
  53.     property    CreateAs : TCreateAs read  FCreateAs
  54.                                      write FCreateAs ;
  55.     property    Singleton : boolean read FBoolSingleton
  56.                                     write FBoolSingleton ;
  57.   end ;
  58.  
  59.   // Used when a TObject descendant is registered
  60.   //----------------------------------------------------------------------------
  61.   TClassMappingObject = class( TClassMappingAbstract )
  62.   private
  63.     FClassRef     : TObjectClassRef ;  // TObject class reference
  64.   public
  65.     Constructor CreateExt( const pStrClassID : string ;
  66.                   pClassRef : TObjectClassRef ;
  67.                   const pBoolSingleton : boolean ) ;
  68.     property    ClassRef : TObjectClassRef read FClassRef
  69.                                            write FClassRef ;
  70.   end ;
  71.  
  72.   // Used when a TComponent descendant is registered
  73.   //----------------------------------------------------------------------------
  74.   TClassMappingComponent = class( TClassMappingAbstract )
  75.   private
  76.     FClassRef     : TComponentClassRef ;  // TComponent class reference
  77.   public
  78.     Constructor CreateExt( const pStrClassID : string ;
  79.                   pClassRef : TComponentClassRef ;
  80.                   const pBoolSingleton : boolean ) ;
  81.     property    ClassRef : TComponentClassRef read FClassRef
  82.                                            write FClassRef ;
  83.   end ;
  84.  
  85.   // The abstract factory
  86.   //----------------------------------------------------------------------------
  87.   TFactoryAbstract = class( TObject )
  88.   private
  89.     FClassMappings : TStringList ;  // List of registered classes
  90.     FObjectCache   : TStringList ;  // Cache of already created objects
  91.   protected
  92.     // Create an instance of our class, or return a pointer to the existing
  93.     // instance if already created. This function is protected to force
  94.     // you to create a public implementation in a concrete class.
  95.     Function   CreateInstance( const pStrClassID : string ) :
  96.                                                    TObject ;
  97.   public
  98.     Constructor Create ; virtual ;
  99.     Destructor Destroy ; override ;
  100.     // Register a TObject descendant
  101.     Procedure  RegisterClass( const pStrClassID : string;
  102.                               pClassRef : TObjectClassRef ;
  103.                               const pBoolSingleton : boolean = false ) ; overload ;
  104.     // Register a TComponent descendant
  105.     Procedure  RegisterClass( const pStrClassID : string;
  106.                               pClassRef : TComponentClassRef ;
  107.                               const pBoolSingleton : boolean = false ) ; overload ;
  108.   end ;
  109.  
  110. implementation
  111. uses
  112.   SysUtils   // UpperCase
  113.   ,Dialogs   // MessageDlg
  114.   ;
  115.  
  116. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  117. // *
  118. // * TClassMappingObject: Hold information about how to create a TObject
  119. // *                      descendant.
  120. // *
  121. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  122. constructor TClassMappingObject.CreateExt(
  123.                   const pStrClassID : string;
  124.                   pClassRef: TObjectClassRef ;
  125.                   const pBoolSingleton : boolean ) ;
  126. begin
  127.   Create ;
  128.   ClassID  := pStrClassID ;
  129.   ClassRef := pClassRef  ;
  130.   CreateAs := caTObject ;
  131.   Singleton := pBoolSingleton ;
  132. end;
  133.  
  134. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  135. // *
  136. // * TClassMappingComponent: Hold information about how to create a
  137. // *                         TComponent descendant.
  138. // *
  139. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  140. constructor TClassMappingComponent.CreateExt(
  141.                   const pStrClassID: string;
  142.                   pClassRef: TComponentClassRef ;
  143.                   const pBoolSingleton : boolean ) ;
  144. begin
  145.   Create ;
  146.   ClassID  := pStrClassID ;
  147.   ClassRef := pClassRef  ;
  148.   CreateAs := caTComponent ;
  149.   Singleton := pBoolSingleton ;
  150. end;
  151.  
  152. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  153. // *
  154. // * TFactoryAbstract: The abstract factory.
  155. // *                   Used to create TObject and TComponent descendants.
  156. // *
  157. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  158. constructor TFactoryAbstract.Create;
  159. begin
  160.   inherited ;
  161.   FClassMappings := TStringList.Create ;
  162.   FObjectCache   := TStringList.Create ;
  163. end;
  164.  
  165. //------------------------------------------------------------------------------
  166. destructor TFactoryAbstract.Destroy;
  167. var i : integer ;
  168. begin
  169.  
  170.   // Scan through FClassMappings,
  171.   // and free any associated objects
  172.   for i := 0 to FClassMappings.Count - 1 do
  173.     TObject( FClassMappings.Objects[i] ).Free ;
  174.   // Free FClassMappings
  175.   FClassMappings.Free ;
  176.  
  177.   // Free any objects in the cache
  178.   for i := 0 to FObjectCache.Count - 1 do
  179.     TObject( FObjectCache.Objects[i] ).Free ;
  180.   FObjectCache.Free ;
  181.  
  182.   // Call inherited
  183.   inherited ;
  184.  
  185. end;
  186.  
  187. // Register a class mapping for a TObject descendant.
  188. //------------------------------------------------------------------------------
  189. procedure TFactoryAbstract.RegisterClass(
  190.                                const pStrClassID: string;
  191.                                pClassRef: TObjectClassRef ;
  192.                                const pBoolSingleton : boolean );
  193. var i : integer ;
  194.     lClassMapping : TClassMappingObject ;
  195.     lStrClassID : string ;
  196. begin
  197.   lStrClassID := upperCase( pStrClassID ) ;
  198.  
  199.   // Does the class mapping alread exist?
  200.   i := FClassMappings.IndexOf( lStrClassID );
  201.  
  202.   // If yes, report an error.
  203.   // We do not raise an exception here as we may be inside an
  204.   // initialization section.
  205.   if i <> -1 then begin
  206.     messageDlg( 'Registering a duplicate ' +
  207.                 'class mapping <' +
  208.                 pStrClassID + '>',
  209.                 mtInformation,
  210.                 [mbOK],
  211.                 0 ) ;
  212.     Exit ; //==>
  213.   end ;
  214.  
  215.   // Create the class mapping object
  216.   lClassMapping := TClassMappingObject.CreateExt(
  217.                       lStrClassID,
  218.                       pClassRef,
  219.                       pBoolSingleton ) ;
  220.  
  221.   // Add the class mapping object to the list
  222.   FClassMappings.AddObject( upperCase( pStrClassID ),
  223.                              lClassMapping ) ;
  224.  
  225. end;
  226.  
  227. // Register a class mapping for a TComponent descendant.
  228. //------------------------------------------------------------------------------
  229. procedure TFactoryAbstract.RegisterClass(
  230.                                   const pStrClassID: string;
  231.                              pClassRef: TComponentClassRef ;
  232.                              const pBoolSingleton : boolean = false );
  233. var i : integer ;
  234.     lClassMapping : TClassMappingComponent ;
  235.     lStrClassID : string ;
  236. begin
  237.   lStrClassID := upperCase( pStrClassID ) ;
  238.  
  239.   // Does the class mapping already exist?
  240.   i := FClassMappings.IndexOf( lStrClassID );
  241.  
  242.   // If yes, report an error.
  243.   // We do not raise an exception here as we may be inside an
  244.   // initialization section.
  245.   if i <> -1 then begin
  246.     messageDlg( 'Registering a duplicate ' +
  247.                 'class mapping <' +
  248.                 pStrClassID + '>',
  249.                 mtInformation,
  250.                 [mbOK],
  251.                 0 ) ;
  252.     Exit ; //==>
  253.   end ;
  254.  
  255.   // Create a reportMapping object
  256.   lClassMapping := TClassMappingComponent.CreateExt(
  257.                       lStrClassID,
  258.                       pClassRef,
  259.                       pBoolSingleton ) ;
  260.  
  261.   // Add the reportName, and reportMapping object to the list
  262.   FClassMappings.AddObject( upperCase( pStrClassID ),
  263.                              lClassMapping ) ;
  264.  
  265. end;
  266.  
  267. // Either look up an existing instance of the object in the cache, or
  268. // create a new one. CreateInstance should only be called from a concrete
  269. // descendant of TFactoryAbstract.
  270. //------------------------------------------------------------------------------
  271. function TFactoryAbstract.CreateInstance(
  272.                               const pStrClassID : string):
  273.                               TObject ;
  274. var lIntCacheIndex   : integer ;
  275.     lIntMappingIndex : integer ;
  276.     lStrClassID      : string ;
  277.     lClassMapping    : TClassMappingAbstract ;
  278. begin
  279.  
  280.   // Get a temporary copy of ClassID, in upper case
  281.   lStrClassID := upperCase( pStrClassID ) ;
  282.  
  283.   // Does the class mapping exist?
  284.   lIntMappingIndex := FClassMappings.IndexOf( lStrClassID );
  285.  
  286.   // If not, then raise an exception
  287.   // We can raise an exception here as we are not likely to be inside
  288.   // initialization code
  289.   if lIntMappingIndex = -1 then
  290.     Raise Exception.Create( 'Request for invalid report ' +
  291.                             'name <' +
  292.                             pStrClassID + '>' ) ;
  293.  
  294.   // Is the object already in the cache?
  295.   // Yes, then return the cahced copy
  296.   // No, then create one
  297.   lIntCacheIndex := FObjectCache.IndexOf( lStrClassID );
  298.  
  299.   // The object is not already in the cache
  300.   if lIntCacheIndex = -1 then begin
  301.     // Get a pointer to the correct class mapping
  302.     lClassMapping := TClassMappingAbstract(
  303.                 FClassMappings.Objects[lIntMappingIndex] ) ;
  304.  
  305.     // Do we create this object as a TComponent or a TObject?
  306.     if lClassMapping.CreateAs = caTComponent then
  307.       result :=
  308.         TClassMappingComponent( lClassMapping ).ClassRef.Create( nil )
  309.     else
  310.       result :=
  311.         TClassMappingObject( lClassMapping ).ClassRef.Create ;
  312.  
  313.     // If this class is to be cached, then add it to the list
  314.     if lClassMapping.Singleton then
  315.       FObjectCache.AddObject( lStrClassID, result ) ;
  316.  
  317.   // The object is already in the cache
  318.   end else begin
  319.     // So return the existing copy
  320.     result := FObjectCache.Objects[ lIntCacheIndex ] ;
  321.  
  322.   end ;
  323.  
  324. end ;
  325.  
  326. end.
  327.  
  328.